#ifndef GAMEENGINE_GEOMETRY_COORDINATESYSTEMS_TRANSFORMER3D_H
#define GAMEENGINE_GEOMETRY_COORDINATESYSTEMS_TRANSFORMER3D_H

#include <GameEngine/Geometry/geometry_settings.h>

#include <GameEngine/Geometry/Location/point3d.h>
#include <GameEngine/Geometry/Location/vector3d.h>
#include <GameEngine/Geometry/Core/angle.h>


#ifdef GAMEENGINE_NAMESPACES
namespace GameEngine {
#endif

namespace Transformer3D {
	//! Index in the 4x3 matrix of a three-dimensional transformer
	enum IndexRow {
		//! First index
		FirstRow = 0,
		//! Second index
		SecondRow = 1,
		//! Third index
		ThirdRow = 2
	};
	//! Index in the 4x3 matrix of a three-dimensional transformer
	enum IndexColumn {
		//! First index
		FirstColumn = 0,
		//! Second index
		SecondColumn = 1,
		//! Third index
		ThirdColumn = 2,
		//! Fourth index
		FourthColumn = 3
	};
}

//! Class used to transform points between two 3D coordinate systems
/*!
 *  This class is a wrapper to a three-dimensional rotation matrix followed by a point
 *  translation. It provides convenience functions that allow to build the tranformation
 *  matrix from points that are known both in the source and in the destination spaces.
 *
 @sa Class Transformer2d for 2D transformations of spatial coordinates and class
     Transformer3dOrientation for transformation of 3D orientations.
 @note Most algorithms expect floating point operations.
       Type T should therefore not be an integer type
 */
template <class T>
class Transformer3d {

public:
	Transformer3d();
	Transformer3d(const Point3d<T>& from1, const Point3d<T>& from2, const Point3d<T>& from3, const Point3d<T>& from4,
		const Point3d<T>& to1, const Point3d<T>& to2, const Point3d<T>& to3, const Point3d<T>& to4);
	Transformer3d(const Transformer3d& rhs);
	virtual ~Transformer3d();
	Transformer3d& operator=(const Transformer3d& rhs);

	bool set_transformation(const Point3d<T>& from1, const Point3d<T>& from2, const Point3d<T>& from3, const Point3d<T>& from4,
		const Point3d<T>& to1, const Point3d<T>& to2, const Point3d<T>& to3, const Point3d<T>& to4);
	bool translate(const Vector3d<T>& offset);
	bool rotate(const Angle<T>& angle, const Vector3d<T>& axis);

	T matrix(Transformer3D::IndexRow row, Transformer3D::IndexColumn column) const;
	T& matrix(Transformer3D::IndexRow row, Transformer3D::IndexColumn column);

	Point3d<T> transform(const Point3d<T>& from) const;

	Transformer3d inverse(bool* ok = nil) const;

protected:
	//! Transformation matrix
	T matrix_[4][3];
};

#ifdef GAMEENGINE_NAMESPACES
} // namespace GameEngine
#endif

#include <GameEngine/Geometry/CoordinateSystems/transformer3d.hpp>

#endif
